/*
 * Copyright 2012 Igor Benicio de Mesquita
 * benizzio@gmail.com
 * 
 * This file is part of fleaNJECT.
 * 
 * fleaNJECT is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as 
 * published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) any later version.
 * 
 * fleaNJECT is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with fleaNJECT.  If not, see <http://www.gnu.org/licenses/>.
 */

package fleanject.di;

import java.util.HashMap;
import java.util.Map;

import fleanject.di.impl.AnnotationComponentFactory;
import fleanject.di.impl.AnnotationConfiguration;


public abstract class AbstractDIContext {
	
	private Map<String, Object> beanMap;
	
	private Assembler assembler;
	
	private boolean devMode = true;
	
	private void startContext() {
		
		Map<String, Object> nonComponentDependencyMap = this.getNonComponentDependencyMap();
		
		if(nonComponentDependencyMap != null) {
			this.beanMap = new HashMap<String, Object>(nonComponentDependencyMap);
		}
		else { 
			this.beanMap = new HashMap<String, Object>(); 
		}
		
		AbstractComponentFactory abstractComponentFactory  = this.getComponentFactoryInstance();
		
		if(devMode){
			ConfigurationValidator configurationValidator = abstractComponentFactory.createConfigurationValidator();
			configurationValidator.validateConfiguration(getConfiguration(), nonComponentDependencyMap);
		}
		
		this.assembler = abstractComponentFactory.createAssembler();
		this.assembler.configure(getConfiguration());
	}
	
	protected abstract Map<String, Object> getNonComponentDependencyMap();
	
	protected abstract AbstractConfiguration getConfiguration();
	
	private AbstractComponentFactory getComponentFactoryInstance() {
		
		AbstractConfiguration configuration = getConfiguration();
		if(configuration == null) { throw new NullPointerException("DI configuration is null"); }
		
		if(configuration instanceof AnnotationConfiguration) {
			return new AnnotationComponentFactory();
		}
		else {
			throw new UnsupportedOperationException("Configuration not supported (" + configuration.getClass().getName() + ")");
		}
	}
	
	public Object getBean(String name) { 
		
		if(this.beanMap == null) {
			this.startContext();
		}
		
		if(this.beanMap.containsKey(name)) {
			return this.beanMap.get(name);
		}
		else {
			return this.assembler.getOrAssembleInto(name, this.beanMap);
		}
	}

	protected void setDevMode(boolean devMode) {
		this.devMode = devMode;
	}

	public boolean isDevMode() {
		return devMode;
	}
}